package com.bc.bcapi.service;

import com.bc.bcapi.dao.T_Account_logMapper;
import com.bc.bcapi.dao.T_Inner_transMapper;
import com.bc.bcapi.dao.T_TxhashMapper;
import com.bc.bcapi.dao.T_Wallet_infoMapper;
import com.bc.bcapi.utils.web3j.ERC20TransactionModel;
import com.bc.bcapi.utils.web3j.TransModel;
import com.bc.bcapi.utils.web3j.Util;
import com.bc.bccore.web3j.WalletService;
import com.bc.bcmodel.domain.*;
import com.bc.bcmodel.req.TxMessage;
import com.bc.commoncore.util.DateUtil;
import com.bc.commonentity.enums.SeqNameEnum;
import com.bc.bcapi.utils.Ognl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;

@Service
public class RechargeService {
    @Resource
    T_OrderService t_orderService;
    @Resource
    T_Account_logMapper t_account_logMapper;
    @Resource
    T_Wallet_infoMapper t_wallet_infoMapper;
    @Resource
    T_SequenceService t_sequenceService;
    @Resource
    T_Inner_transMapper t_inner_transMapper;
    @Resource
    T_TxhashMapper t_txhashMapper;

    private static final Logger LOGGER = LoggerFactory.getLogger(RechargeService.class);

    public void recharge(T_User_walletModel t_user_walletModel, ERC20TransactionModel transactionModel, TransModel transModel) throws Exception {
        T_Account_logModel recharge_logModel = record(t_user_walletModel, transactionModel, transModel);
        if (recharge_logModel != null) {
            if (transModel.getContract_address().equals(Util.getETHADDRESS()))
                transCold(t_user_walletModel, transModel, recharge_logModel);
            else transGas(t_user_walletModel, transModel, recharge_logModel);
        }
    }

    /*
    1. t_account_log插入充值记录
    2. t_wallet_info amount += c
     */
    @Transactional(rollbackFor = {
            Exception.class}, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public T_Account_logModel record(T_User_walletModel t_user_walletModel, ERC20TransactionModel transactionModel, TransModel transModel) {
        if (transModel.getContractModel() == null) {
            LOGGER.info(t_user_walletModel.toString());
            LOGGER.info(transactionModel.toString());
            LOGGER.info(transModel.toString());
            LOGGER.info("not a vaild contract");
            return null;
        } else {
            String contract = transModel.getContractModel().getContract_id();
            String user_id = t_user_walletModel.getUser_id();
            String address = transModel.getTo();

            BigDecimal amount = Util.Wei2Token(transModel.getValue(), transModel.getContractModel().getDigit());
            T_Account_logModel recharge_logModel = t_orderService.init_account_log(
                    user_id, amount, contract, "充值"
            );
            t_account_logMapper.insert(recharge_logModel);

            HashMap<String, Object> userWalletMap = new HashMap<>();
            userWalletMap.put("user_id", user_id);
            userWalletMap.put("contract_id", contract);
            T_Wallet_infoModel exist_wallet_infoModel = t_wallet_infoMapper.selectForUpdate(userWalletMap);
            if (exist_wallet_infoModel != null) {
                //存在
                HashMap<String, Object> updateWalletMap = new HashMap<>();
                updateWalletMap.put("id", exist_wallet_infoModel.getId());
                updateWalletMap.put("amount", amount);
                t_wallet_infoMapper.recharge(updateWalletMap);
            } else {
                //新建
                T_Wallet_infoModel new_wallet_info = new T_Wallet_infoModel();
                new_wallet_info.setUser_id(user_id);
                new_wallet_info.setContract_id(contract);
                new_wallet_info.setWallet_address(address);
                new_wallet_info.setAmount(amount);
                new_wallet_info.setStatus("1");
                t_wallet_infoMapper.insert(new_wallet_info);
            }
            return recharge_logModel;
        }
    }

    @Transactional(rollbackFor = {
            Exception.class}, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public void transCold(T_User_walletModel t_user_walletModel, TransModel transModel, T_Account_logModel recharge_logModel) throws Exception {
        //eth直接转冷
        BigDecimal reChargeValue = Util.convertWei2Eth(transModel.getValue());
        BigInteger gasPrice = Util.estimateGasPrice();
        BigInteger gasLimit = Util.getETHGASLIMIT();
        BigInteger gasInWei = gasPrice.multiply(gasLimit);
        BigInteger value = transModel.getValue().subtract(gasInWei);
        if (value.compareTo(BigInteger.ZERO) <= 0) return;
        //if (value.compareTo(BigInteger.ZERO) <= 0) value = BigInteger.ZERO;
        String spk = t_user_walletModel.getPrivate_key();
        String salt = t_user_walletModel.getUser_id();
        String pk = Util.getUserPk(spk, salt);
        String to = Util.getColdWalletAddress();

        String txhash = WalletService.getInstance().sendETHTransaction(pk, to, value, gasPrice, gasLimit);
        if (Ognl.isBlank(txhash)) throw new Exception("send cold wallet error");
        //t_inner_trans
        T_Inner_transModel transColdModel = new T_Inner_transModel();
        String inner_tran_id = t_sequenceService.genSequence(SeqNameEnum.INNER_TRANS_ID);
        transColdModel.setInner_trans_id(inner_tran_id);
        String token_name = transModel.getContractModel().getContract_id();
        transColdModel.setWithdraw_account(reChargeValue);
        transColdModel.setToken_name(token_name);
        transColdModel.setPay_status(0);
        transColdModel.setGas_account(Util.convertWei2Eth(gasInWei));
        transColdModel.setActual_account(Util.convertWei2Eth(value));
        transColdModel.setPay_address(t_user_walletModel.getWallet_address());
        transColdModel.setDest_address(to);
        transColdModel.setRecharge_log_id(recharge_logModel.getId());
        t_inner_transMapper.insert(transColdModel);

        //t_txhash
        T_TxhashModel txhashModel = new T_TxhashModel();
        txhashModel.setTxhash(txhash);
        txhashModel.setWithdraw_id(inner_tran_id);
        txhashModel.setTranstype(2);
        t_txhashMapper.insert(txhashModel);
    }

    @Transactional(rollbackFor = {
            Exception.class}, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public void transGas(T_User_walletModel t_user_walletModel, TransModel transModel, T_Account_logModel recharge_logModel) throws Exception {
        //向帐号转gas
        BigInteger gasPrice = Util.estimateGasPrice();
        BigInteger gasLimit = Util.getETHGASLIMIT();
        BigInteger gasInWei = gasPrice.multiply(gasLimit);
        BigInteger transValue = gasPrice.multiply(Util.getCONTRACTGASLIMIT());
        BigInteger totalValue = gasInWei.add(transValue);
        String to = transModel.getTo();
        String from = Util.getColdWalletAddress();
        String pk = Util.getColdWalletPk();

        String txhash = WalletService.getInstance().sendETHTransaction(pk, to, transValue, gasPrice, gasLimit);
        if (Ognl.isBlank(txhash)) throw new Exception("send cold wallet error");
        //t_inner_trans
        T_Inner_transModel transColdModel = new T_Inner_transModel();
        String inner_tran_id = t_sequenceService.genSequence(SeqNameEnum.INNER_TRANS_ID);
        transColdModel.setInner_trans_id(inner_tran_id);
        String token_name = Util.getETHID();
        transColdModel.setWithdraw_account(Util.convertWei2Eth(totalValue));
        transColdModel.setToken_name(token_name);
        transColdModel.setPay_status(0);
        transColdModel.setGas_account(Util.convertWei2Eth(gasInWei));
        transColdModel.setActual_account(Util.convertWei2Eth(transValue));
        transColdModel.setPay_address(from);
        transColdModel.setDest_address(to);
        transColdModel.setRecharge_log_id(recharge_logModel.getId());
        t_inner_transMapper.insert(transColdModel);

        //t_txhash
        T_TxhashModel txhashModel = new T_TxhashModel();
        txhashModel.setTxhash(txhash);
        txhashModel.setWithdraw_id(inner_tran_id);
        txhashModel.setTranstype(3);
        t_txhashMapper.insert(txhashModel);
    }

    @Transactional(rollbackFor = {
            Exception.class}, isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public int recordEos(TxMessage txMessage) {
        if (txMessage == null) {
            return 0;
        }
//            String contract = transModel.getContractModel().getContract_id();
        String user_id = txMessage.getUserId();
        String address = txMessage.getReceiver();
        BigDecimal amount = new BigDecimal(txMessage.getQuantity());
        String token_name = txMessage.getSymbol();
        String contract = "EOS";
//            BigDecimal amount = Util.Wei2Token(transModel.getValue(), transModel.getContractModel().getDigit());
//            T_Account_logModel recharge_logModel = t_orderService.init_account_log(
//                    user_id, amount, contract, "充值"
//            );
//            t_account_logMapper.insert(recharge_logModel);
        /*充值记录*/
        T_Account_logModel t_account_logModel = new T_Account_logModel();
        t_account_logModel.setTrans_id(txMessage.getTxId());
        t_account_logModel.setAccount_no(user_id);
        t_account_logModel.setAmount(amount);
        t_account_logModel.setAmount_type(token_name);
        t_account_logModel.setType("充值");
        t_account_logModel.setTrans_memo("");
        t_account_logModel.setOut_order_no("");
        t_account_logModel.setCreate_time(DateUtil.getToday());
        t_account_logModel.setModify_time(DateUtil.getToday());
        t_account_logModel.setUser_id(user_id);
        t_account_logModel.setWallet_address("");
        t_account_logModel.setStatus("1");

        HashMap<String, Object> userWalletMap = new HashMap<>();
        userWalletMap.put("user_id", user_id);
        userWalletMap.put("contract_id", contract);
        T_Wallet_infoModel exist_wallet_infoModel = t_wallet_infoMapper.selectForUpdate(userWalletMap);
        if (exist_wallet_infoModel != null) {
            //存在
            HashMap<String, Object> updateWalletMap = new HashMap<>();
            updateWalletMap.put("id", exist_wallet_infoModel.getId());
            updateWalletMap.put("amount", amount);
            t_wallet_infoMapper.recharge(updateWalletMap);
        } else {
            //新建
            T_Wallet_infoModel new_wallet_info = new T_Wallet_infoModel();
            new_wallet_info.setUser_id(user_id);
            new_wallet_info.setContract_id(contract);
            new_wallet_info.setWallet_address(address);
            new_wallet_info.setAmount(amount);
            new_wallet_info.setStatus("1");
            t_wallet_infoMapper.insert(new_wallet_info);
        }
        return 1;
    }

}
